package com.cskaoyan.mall.promo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.cskaoyan.mall.common.constant.RedisConst;
import com.cskaoyan.mall.common.execption.BusinessException;
import com.cskaoyan.mall.common.util.DateUtil;
import com.cskaoyan.mall.order.dto.OrderDetailDTO;
import com.cskaoyan.mall.order.dto.OrderTradeDTO;
import com.cskaoyan.mall.order.query.OrderInfoParam;
import com.cskaoyan.mall.promo.api.dto.SeckillGoodsDTO;
import com.cskaoyan.mall.promo.client.OrderApiClient;
import com.cskaoyan.mall.promo.client.UserApiClient;
import com.cskaoyan.mall.promo.constant.SeckillCodeEnum;
import com.cskaoyan.mall.promo.constant.SeckillGoodsStatus;
import com.cskaoyan.mall.promo.converter.SeckillGoodsConverter;
import com.cskaoyan.mall.promo.mapper.SeckillGoodsMapper;
import com.cskaoyan.mall.promo.model.SeckillGoods;
import com.cskaoyan.mall.promo.service.PromoService;
import com.cskaoyan.mall.promo.util.LocalCacheHelper;

import com.cskaoyan.mall.user.dto.UserAddressDTO;
import org.redisson.api.*;
import org.redisson.client.codec.StringCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@SuppressWarnings("all")
public class PromoServiceImpl implements PromoService {

    @Autowired
    RedissonClient redissonClient;
    @Autowired
    UserApiClient userApiClient;
    @Autowired
    OrderApiClient orderApiClient;
    @Autowired
    SeckillGoodsConverter seckillGoodsConverter;
    @Autowired
    SeckillGoodsMapper seckillGoodsMapper;


    /**
     * 初始化秒杀商品库存状态标志位，把秒杀商品列表信息导入Redis
     */
    @Override
    public void importIntoRedis() {
        // 1 查询出参与当天秒杀活动的所有秒杀商品
        List<SeckillGoods> seckillGoodsList = querySeckillGoodsList();
        // 2 初始化库存状态标志位
        for (SeckillGoods seckillGoods : seckillGoodsList) {
            LocalCacheHelper.put(seckillGoods.getSkuId().toString(), "1");
        }
    }

    /**
     * 查询当天参与秒杀活动的秒杀商品列表
     */
    private List<SeckillGoods> querySeckillGoodsList() {
        /*
            1. 审核通过：status = CHECKED_PASS
            2. 今天开始：DATE_FORMAT(start_time,'%Y-%m-%d') = new Date()
            3. 库存大于0：stock_count>0
        */
        QueryWrapper<SeckillGoods> seckillGoodsQueryWrapper = new QueryWrapper<>();
        seckillGoodsQueryWrapper.eq("status", SeckillGoodsStatus.CHECKED_PASS.name())
                .eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()))
                .gt("stock_count", 0);
        List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsQueryWrapper);
        return seckillGoodsList;
    }

    /**
     * 返回全部列表
     */
    @Override
    public List<SeckillGoodsDTO> findAll() {
        // 查询秒杀商品列表
        List<SeckillGoods> seckillGoodsList = querySeckillGoodsList();
        return seckillGoodsConverter.convertSeckillGoodsList(seckillGoodsList);
    }

    /**
     * 根据秒杀商品ID获取商品详情实体
     *
     * @param skuId
     */
    @Override
    public SeckillGoodsDTO getSeckillGoodsDTO(Long skuId) {
        LambdaQueryWrapper<SeckillGoods> seckillGoodsQueryWrapper = new LambdaQueryWrapper<>();
        seckillGoodsQueryWrapper.eq(SeckillGoods::getSkuId, skuId);
        SeckillGoods seckillGoods = seckillGoodsMapper.selectOne(seckillGoodsQueryWrapper);
        return seckillGoodsConverter.convertSeckillGoodsToDTO(seckillGoods);
    }

    /**
     * 组装秒杀商品订单结算页数据
     */
    @Override
    public OrderTradeDTO getTradeData(String userId, Long skuId) {
        // 需要返回的订单结算页对象
        OrderTradeDTO orderTradeDTO = new OrderTradeDTO();

        // 1 用户的地址列表
        List<UserAddressDTO> userAddressListByUserId = userApiClient.findUserAddressListByUserId(userId);
        // 添加到 用户地址列表
        orderTradeDTO.setUserAddressList(userAddressListByUserId);

        // 2 用户待下单的商品明细列表
        SeckillGoodsDTO seckillGoodsDTO = getSeckillGoodsDTO(skuId);
        // 秒杀场景下，商品数量是固定的只有一个
        OrderDetailDTO orderDetailDTO =
                seckillGoodsConverter.secondKillGoodsToOrderDetailDTO(seckillGoodsDTO, 1);
        // 添加到 订单明细列表
        orderTradeDTO.setDetailArrayList(Arrays.asList(orderDetailDTO));

        // 3 订单条目数量和总金额
        orderTradeDTO.setTotalNum(1);
        orderTradeDTO.setTotalAmount(orderDetailDTO.getOrderPrice());
        return orderTradeDTO;
    }

    @Override
    @Transactional
    public void submitOrder(OrderInfoParam orderInfo) {
        // 仅仅实现业务功能
        // 1 判断用户有没有重复下单
        RSet<Long> set = redissonClient.getSet(RedisConst.PROMO_USER_ORDERED_FLAG + orderInfo.getUserId());
        Long skuId = orderInfo.getOrderDetailList().get(0).getSkuId();
        // 添加是否成功
        boolean isOk = set.tryAdd(skuId);
        if (!isOk) {
            // 同一商品重复下单
            throw new BusinessException(SeckillCodeEnum.SECKILL_DUPLICATE_TRADE);
        }
        // 2 扣减库存
        Integer effctiveRow = seckillGoodsMapper.decreaseStock(skuId, 1);
        if (effctiveRow <= 0) {
            // 库存扣减完毕，商品已经售罄
            LocalCacheHelper.put(skuId.toString(), "0");
            throw new BusinessException(SeckillCodeEnum.SECKILL_FINISH);
        }
        // 3 调用订单服务，生成订单
        try {
            orderApiClient.submitOrder(orderInfo);
        } catch (Exception e) {
            e.printStackTrace();
            // 提交订单失败，需要重新下单，需要先删除商品的重复下单标记
            set.remove(skuId);
        }


    }

    /**
     * 清理Redis缓存
     */
    @Override
    public void clearCache() {
        // 1 需要把当天参与秒杀活动的商品状态 改为已完成状态
        /* 1）当天的
           2) 秒杀商品的状态 Chenked_pass
           3) 时间要大于结束时间
        */
        UpdateWrapper<SeckillGoods> seckillGoodsUpdateWrapper = new UpdateWrapper<>();
        seckillGoodsUpdateWrapper.eq("DATA_FORMAT(end_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()))
                .eq("status", SeckillGoodsStatus.CHECKED_PASS.name())
                .lt("end_time", new Date());
        SeckillGoods seckillGoods = new SeckillGoods();
        seckillGoods.setStatus(SeckillGoodsStatus.FINISHED.name());
        seckillGoodsMapper.update(seckillGoods, seckillGoodsUpdateWrapper);

        // 2 库存状态标志位
        LocalCacheHelper.removeAll();
    }

    /**
     * 前端轮训，检查用户下单信息
     */
    @Override
    public boolean checkOrder(Long skuId, String userId) {

        return true;
    }


    @Override
    public void submitOrderInTransaction(OrderInfoParam orderInfo) {

    }


}
